package xyz.xtt.asset.mq;

import static xyz.xtt.common.asset.AssertUtils.isFalse;
import static xyz.xtt.common.asset.AssertUtils.isNull;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.google.common.primitives.Longs;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.asset.api.enums.AssetNoStatusEnum;
import xyz.xtt.asset.api.enums.AssetNoTypeEnum;
import xyz.xtt.asset.api.enums.AssetTypeEnum;
import xyz.xtt.asset.api.enums.OwnerTypeEnum;
import xyz.xtt.asset.client.request.ConfirmTransactionRequest;
import xyz.xtt.asset.client.request.MakeTransactionRequest;
import xyz.xtt.asset.constants.ErrorMessage;
import xyz.xtt.asset.entity.TblAsset;
import xyz.xtt.asset.entity.TblAssetNo;
import xyz.xtt.asset.entity.TblAssetTransaction;
import xyz.xtt.asset.service.IInnerService;
import xyz.xtt.asset.service.INftService;
import xyz.xtt.asset.service.IRoseService;
import xyz.xtt.asset.service.ITblAssetCardService;
import xyz.xtt.asset.service.ITblAssetGroupService;
import xyz.xtt.asset.service.ITblAssetNoService;
import xyz.xtt.asset.service.ITblAssetService;
import xyz.xtt.asset.service.ITblAssetTransactionService;
import xyz.xtt.asset.service.ITblRemintAccountService;
import xyz.xtt.equity.api.enums.TblBenefitPackageEnum;
import xyz.xtt.equity.api.enums.UserBenefitSourceTypeEnum;
import xyz.xtt.equity.client.request.SendAssetNoBenefitRequest;
import xyz.xtt.equity.client.request.SendFreeBenefitPackageRequest;
import xyz.xtt.pay.api.dto.BusinessOrderStatusChangeMsg;
import xyz.xtt.pay.api.enums.PayOrderBusinessTypeEnum;
import xyz.xtt.pay.client.response.BusinessOrderResponse;
import xyz.xtt.pay.client.response.TblPayOrderDto;

/**
 * @author dale
 * @date 2025/3/18
 **/
@RefreshScope
@Slf4j
@Component
@RocketMQMessageListener(topic = "${rocketmq.business.order.status.change.topic:nft_pay_business_order_status_change_topic}", selectorExpression = "normal_pay_success||rose_mint_pay_success||c_to_c_pay_success||buy_asset_1155_pay_success", consumerGroup = "${rocketmq.consumer.group.asset.nft.purchase.pay.success:nft_asset_nft_purchase_pay_success_group}")
public class NftPurchaseBusinessOrderPaySuccessConsumer implements RocketMQListener<MessageExt> {
	@Autowired
	private ITblAssetTransactionService iTblAssetTransactionService;
	@Autowired
	private INftService nftService;
	@Autowired
	private IRoseService iRoseService;
	@Autowired
	private ITblAssetService iTblAssetService;
	@Autowired
	private ITblAssetNoService iTblAssetNoService;
	@Autowired
	private ITblRemintAccountService iTblRemintAccountService;
	@Autowired
	private ITblAssetCardService tblAssetCardService;
	@Autowired
	private IInnerService iInnerService;
	@Autowired
	private ITblAssetGroupService iTblAssetGroupService;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void onMessage(MessageExt msg) {
		String msgId = msg.getMsgId();
		String tags = msg.getTags();
		byte[] body = msg.getBody();
		String message = new String(body, StandardCharsets.UTF_8);
		log.info("NftPurchaseBusinessOrderPaySuccessConsumer msgId:{} tags:{} message: {}", msgId, tags, message);
		if (StringUtils.isEmpty(message)) {
			return;
		}
		if (!JSONUtil.isTypeJSON(message)) {
			log.warn("NftPurchaseBusinessOrderPaySuccessConsumer Received message: {} is not json", message);
			return;
		}

		BusinessOrderStatusChangeMsg statusChangeMsg = JSONUtil.toBean(message, BusinessOrderStatusChangeMsg.class);
		isNull(statusChangeMsg, ErrorMessage.ARGUMENT_NOT_VALID);
		log.info("NftPurchaseBusinessOrderPaySuccessConsumer statusChangeMsg: {} tag:{}", message, tags);
		BusinessOrderResponse businessOrder = iInnerService.businessOrderInfoWithId(statusChangeMsg.getBusinessOrderId());
		isNull(businessOrder, ErrorMessage.BUSINESS_ORDER_NOT_EXISTS);

		TblAssetTransaction transaction = iTblAssetTransactionService.getById(Longs.tryParse(businessOrder.getBusinessRefId()));
		ConfirmTransactionRequest confirmOrderRequest = ConfirmTransactionRequest
				.builder()
				.orderId(transaction.getOrderId())
				.from(Long.valueOf(transaction.getSellerUserId()))
				.to(Long.valueOf(transaction.getBuyerUserId()))
				.assetId(transaction.getAssetId())
				.actTotalPrice(businessOrder.getTotalPrice())
				.build();
		nftService.confirmTransaction(confirmOrderRequest);

		long assetId = Long.valueOf(businessOrder.getGoodsId());
		TblAsset asset = iTblAssetService.infoWithIdByCache(assetId);
		boolean isTopTrade = nftService.isTopTrade(asset, businessOrder.getSellerId());
		if (Objects.equals(asset.getFirstType(), AssetTypeEnum.BLIND_BOX.code())) {
			for (int i = 0; i < businessOrder.getPurchaseNum(); i++) {
				// 盲盒不需要确认交易，开盒后根据开盒结果创建子资产上的交易
				TblAsset unBoxAsset = nftService.unBoxAsset(asset.getId());
				MakeTransactionRequest makeTransactionRequest = MakeTransactionRequest
						.builder()
						.from(businessOrder.getSellerId())
						.to(businessOrder.getAppUserId())
						.num(1)
						.assetId(unBoxAsset.getId())
						.price(BigDecimal.ZERO.toPlainString())
						.expireTimeWithLevel(0)
						.orderType((Objects.equals(asset.getOwnerType(), OwnerTypeEnum.USER.code())
								|| Objects.equals(asset.getOwnerType(), OwnerTypeEnum.AGENT.code())) ? PayOrderBusinessTypeEnum.C_TO_C.name()
										: PayOrderBusinessTypeEnum.BUY_ASSET_1155.name())
						.fees("0")
						.build();
				makeTransactionRequest.setOrderPrice(businessOrder.getTotalPrice());
				makeTransactionRequest.setBizType("nft");
				transaction = nftService.makeTransaction(makeTransactionRequest);
				confirmOrderRequest = ConfirmTransactionRequest
						.builder()
						.orderId(transaction.getOrderId())
						.from(Long.valueOf(transaction.getSellerUserId()))
						.to(Long.valueOf(transaction.getBuyerUserId()))
						.assetId(transaction.getAssetId())
						.actTotalPrice(businessOrder.getTotalPrice())
						.build();
				nftService.confirmTransaction(confirmOrderRequest);

				trySendAssetNoBenefit(businessOrder.getSellerId(), transaction, unBoxAsset, "c_to_c_pay_success", businessOrder.getAppUserId());

				// 加入群聊
				joinAssetGroup(asset, transaction.getOrderId(), businessOrder.getAppUserId());
			}
			return;
		}
		TblPayOrderDto payOrder = iInnerService.fetchPayOrder(statusChangeMsg.getBusinessOrderId());
//		TblPayOrder payOrder = iTblPayOrderService.getPayOrderByBusinessOrder(statusChangeMsg.getBusinessOrderId());
		if (Objects.equals(tags, "c_to_c_pay_success")) {
			// C_TO_C交易成功后进行分账
			TblPayOrderDto payOrderDto = new TblPayOrderDto();
			BeanUtils.copyProperties(payOrder, payOrderDto);
			payOrderDto.setSellerId(businessOrder.getSellerId());
			Boolean handleOrderPaySuccess = iInnerService.handleOrderPaySuccess(payOrderDto);
			log.info("handleOrderPaySuccess：{}", handleOrderPaySuccess);
			if (!isTopTrade) {
				// 非顶级交易，生成铸造权
				iTblRemintAccountService.reMintPayAfter(payOrderDto);
				// 非顶级交易，注销卖家卡牌
				List<TblAssetNo> assetNos = iTblAssetNoService
						.getAssetNoByTrans(transaction.getOrderId(), AssetNoTypeEnum.MINT_BENEFIT, AssetNoStatusEnum.NORMAL);
				if (!CollectionUtils.isEmpty(assetNos)) {
					tblAssetCardService.updateInvalidByAssetNos(assetNos.stream().map(TblAssetNo::getId).toList());
				} else {
					log.error("NftPurchaseBusinessOrderPaySuccessConsumer can not find assetNos by transId:{}", transaction.getOrderId());
				}
			}
		} else if (Objects.equals(tags, "rose_mint_pay_success")) {
			// ROSE_MINT交易成功后进行铸造
			iRoseService.mintRoseAfterPay(businessOrder);

			// 玫瑰花赠送vip月卡
			SendFreeBenefitPackageRequest sendFreeBenefitPackageRequest = new SendFreeBenefitPackageRequest();
			sendFreeBenefitPackageRequest.setPackageCode(TblBenefitPackageEnum.NFT_VIP_MONTH.name());
			sendFreeBenefitPackageRequest.setAppUserId(businessOrder.getAppUserId());
			sendFreeBenefitPackageRequest.setSendNum(1);
			sendFreeBenefitPackageRequest.setSourceType(UserBenefitSourceTypeEnum.BUY_ROSE_SEND_VIP_MONTH.name());
			sendFreeBenefitPackageRequest.setSourceRefId(payOrder.getPayOrderId());
			Boolean result = iInnerService.sendFreeBenefitPackage(sendFreeBenefitPackageRequest);
			isFalse(result, ErrorMessage.ORDER_OPERATE_FAILED);
		}

		trySendAssetNoBenefit(businessOrder.getSellerId(), transaction, asset, tags, businessOrder.getAppUserId());
		// 加入群聊
		joinAssetGroup(asset, transaction.getOrderId(), businessOrder.getAppUserId());

	}

	private void joinAssetGroup(TblAsset asset, Long orderId, Long uid) {
		// 根据资产判断需要加入群信息
		iTblAssetGroupService.paySuccessJoinGroup(asset, orderId, uid);
	}

	private void trySendAssetNoBenefit(Long sellerId, TblAssetTransaction transaction, TblAsset asset, String tags, Long buyerId) {
		if (nftService.isTopTrade(asset, sellerId) && (Objects.equals(tags, "c_to_c_pay_success") || Objects.equals(tags, "buy_asset_1155_pay_success"))) {
			List<TblAssetNo> assetNos = iTblAssetNoService.getAssetNoByTrans(transaction.getOrderId(), AssetNoTypeEnum.ASSET, AssetNoStatusEnum.NORMAL);
			if (!CollectionUtils.isEmpty(assetNos)) {
				SendAssetNoBenefitRequest request = new SendAssetNoBenefitRequest();
				request.setAssetId(asset.getId());
				request.setAssetNoIds(assetNos.stream().map(TblAssetNo::getId).toList());
				request.setReceiverId(buyerId);
				request.setSenderId(sellerId);
				Boolean result = iInnerService.sendAssetNoBenefit(request);
				isFalse(result, ErrorMessage.ORDER_OPERATE_FAILED);
			}
		}
	}
}
